/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package client;

import java.io.*;

import java.net.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.fileInfo;

/**
 *
 * @author user
 */
public class Client {

    private int port;
    public Socket client;
    private String message;
    public String username;
    public String workingdirectory;
    public int fileCount;
    public int fileCountServer;
    public ArrayList<fileInfo> file_info = new ArrayList<fileInfo>();
    public ArrayList<fileInfo> file_info_client = new ArrayList<fileInfo>();

    public Client(int p) {
        this.port = p;
        try {
            client = new Socket("localhost", this.port);
        } catch (UnknownHostException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendMessage(String msg) {
        try {

            PrintWriter out = new PrintWriter(client.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            out.println(msg);
            //out.close();
            //in.close();
            //this.client.close();

        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public ArrayList<String> addFilePaths(ArrayList<fileInfo> fi) {
        ArrayList<String> filepaths = new ArrayList<String>();
        for (int i = 0; i < fi.size(); i++) {
            filepaths.add(fi.get(i).getFile_path());
        }
        return filepaths;
    }

    public void getFileInfoFromServer() {
        String[] pecah1 = this.message.split("###");
        String[] pecah2 = pecah1[0].split(";;;");

        this.username = pecah2[0];
        this.workingdirectory = pecah2[2];
        file_info = new ArrayList<fileInfo>();

        if (pecah1.length > 1){
            String[] files = pecah1[1].split("%%%");
            ArrayList<String> filesArr = new ArrayList<String>();
            filesArr.addAll(Arrays.asList(files));
            this.fileCountServer = filesArr.size() - 1;
            System.out.println("filecount = " + filesArr.size());
            //masukkan info file dari message
            for (int i = 0; i < filesArr.size(); i++) {
                String[] fileinfo = filesArr.get(i).split(";;;");
                file_info.add(new fileInfo(fileinfo[0], Timestamp.valueOf(fileinfo[1])));
//                System.out.println("File path : " + file_info.get(i).getFile_path());
//                System.out.println("Date modified : " + file_info.get(i).getDate_modified().toString());
            }
        }
         else{
            System.out.println("server has no files");
         }
        
    }

    public String ignoreWorkingDir(String full_path){
        String out = full_path.substring(this.workingdirectory.length()+1);
        return out;
    }
    
    public String ignoreServerWorkingDir(String full_path){
        String path = "test\\client\\"+this.username;
        String out = full_path.substring(path.length()+1);
        return out;
    }

    public int cekSyncRequest() {
                //fungsi yang menerima permintaan dari client
        //contoh format message =
        //username;;;working_dir###file_path;;;timestamp%%%file_path;;;timestamp

       //this.getFileInfoFromServer();
        //bandingkan dengan yang di database
        //this.listFileFolder(workingdirectory);
       //add file_info_client
       String[] filecontent = listFileFolder(workingdirectory);
            for (int i = 0; i < filecontent.length - 1; i++) {
                if (filecontent[i] != null) {
                    //this.fileCount = filecontent.length;
                    this.file_info_client.add(new fileInfo(
                            workingdirectory + "\\" + filecontent[i],
                            Timestamp.valueOf(getDateLastModified(workingdirectory + "\\" + filecontent[i]))));
                    //System.out.println("coba print : "+getDateLastModified(workingdirectory + "\\" +filecontent[i]));

                }
            }
        //cek jumlah dan date_modified
        //cek versi
       System.out.println("File info client size = "+this.file_info_client.size());
        boolean serverHasNewest = false;
        boolean clientHasNewest = false;
        //cek dulu jumlahnya
        if (this.file_info.size() > this.file_info_client.size()){
            //server lebih banyak filenya
            serverHasNewest = true;
        }
        else if (this.file_info.size() < this.file_info_client.size()){
            clientHasNewest = true;
        }
         else if (this.file_info.size() == this.file_info_client.size()){
            System.out.println("sama jumlahnya gan");
            System.out.println("file server size = "+ this.file_info.size());
            System.out.println("current workdir = " + this.workingdirectory);
           for(int i=0; i<this.file_info_client.size(); i++){
               
               //ignore file path, sisain filename doang

               ArrayList<fileInfo> fi_client = new ArrayList<fileInfo>();
               ArrayList<fileInfo> fi_server = new ArrayList<fileInfo>();
               //yang client dulu
               for(int j=0; j<this.file_info_client.size(); j++){
                   String filepath = this.ignoreWorkingDir(this.file_info_client.get(j).getFile_path());
                   Timestamp date = this.file_info_client.get(j).getDate_modified();
                   fi_client.add(new fileInfo(filepath,date));
               }
               //terus yg server
               for(int k=0; k<this.file_info.size(); k++){
                   String filepath = this.ignoreServerWorkingDir(this.file_info.get(k).getFile_path());
                   Timestamp date = this.file_info.get(k).getDate_modified();
                   fi_server.add(new fileInfo(filepath,date));
               }
               
               System.out.println("client path #"+i+" : "+ fi_client.get(i).getFile_path());
               System.out.println("server path #"+i+" : "+ fi_server.get(i).getFile_path());
               System.out.println("client date #"+i+" : "+ fi_client.get(i).getDate_modified().toString());
               System.out.println("server date #"+i+" : "+ fi_server.get(i).getDate_modified().toString());
               System.out.println("---------------------------------");
               
               //bandingin date modified dari tiap file
//               if (fi_server.get(i).getFile_path().equalsIgnoreCase(fi_client.get(i).getFile_path())){
//                   System.out.println("idx = " + i);
//                   int idxfoundclient = fi_client.indexOf(fi_server.get(i));
//                   System.out.println("idx client = " + idxfoundclient);
//                   int idxfoundserver = fi_server.indexOf(fi_client.get(i));
//                   System.out.println("idx server = " + idxfoundserver);
//                   System.out.println("Client DATE MODIFIED #"+i+": " + fi_client.get(i).getDate_modified().toString());
//                   System.out.println("Server DATE MODIFIED #"+i+": " + fi_server.get(i).getDate_modified().toString());
                   if (fi_client.get(i).getDate_modified().after(fi_server.get(i).getDate_modified())){
                       System.out.println("client has newest");
                       clientHasNewest = true;
                       break;
                       //berarti client update/download file yg ini
                   }
                   else if (fi_server.get(i).getDate_modified().after(fi_client.get(i).getDate_modified())){
                       System.out.println("server has newest");
                       serverHasNewest = true;
                       break;
                       //berarti si client upload file ini ke server
                   }
                     else{

                     }
//               }
//               else{
//                i++;
//               }
            }
         }
         else{

         }

        //jika yang di client kurang atau ada file di server yang lebih baru versinya, langsung kirim file-file terbaru
        if (/*this.isServerHasMoreFile() || */clientHasNewest){
            return 1;
        }
        else if (serverHasNewest){
            //jika yang di client kurang namun ada file di client yang lebih baru versinya, langsung terima file yang terbaru dari client
            return 2;
        }
         else{
            return 3; //do nothing
         }
    }


        public void requestAllFilesToServer(){
        //kirim message buat minta file terbaru ke client
        //formatnya <username>;;;requestfile
        this.sendMessage(this.username+";;;requestfile;;;"+"C:\\Users\\user\\Documents\\NetBeansProjects\\Progin5\\test");
    }

    public void receiveMessage() {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
            if ((this.message = in.readLine()) != null) {
                System.out.println(message);
                
            }
//        } catch (InterruptedException ex) {
//            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void cekAccepted(){
        this.receiveMessage();
        String[] pecah = this.message.split(";;;");
        if (pecah.length >= 2){
            this.username = pecah[0];
            if (pecah[1].equalsIgnoreCase("accepted")) {
                System.out.println("accepted");
                //looping disini ntar tiap 5 detik
                this.requestAllFilesToServer();
//                    Thread.sleep(500);
                System.out.println("size = " + this.file_info.size());
                //this.sinkronisasi(this.username, "C:\\Users\\user\\Documents\\NetBeansProjects\\Progin5\\test");
                //kirim filenya
                System.out.println("filecount = " + this.fileCount);
                ArrayList<String> filepaths = this.addFilePaths(this.file_info_client);
                //this.sendMultipleFile(filepaths);
            }
        }
         else{

         }
    }

    public void cekSendingFile(){
        this.receiveMessage();
        String[] pecah = this.message.split(";;;");
        if (pecah.length >= 2){
            if (pecah[1].equalsIgnoreCase("sendingfile")){
                //this.receiveFile(this.addFilePaths(file_info_client));
                System.out.println("sinkronisasi...");
                System.out.println("setelah accept : "+ this.message);
                this.getFileInfoFromServer();
                this.sinkronisasi(username, "C:\\Users\\user\\Documents\\NetBeansProjects\\Progin5\\test");
            }
             else{

             }
        }
         else{

         }
    }

    public void cekReceivingFile(){
        this.receiveMessage();
        String[] pecah = this.message.split(";;;");
        if (pecah.length >= 2){
            if (pecah[1].equalsIgnoreCase("receivingfile")){
                ArrayList<String> clientpath = new ArrayList<String>();
                    System.out.println("receiving file....");
                    System.out.println("receiving file client size : "+this.file_info_client.size());
                    this.getFileInfoFromServer();
                    //ubah path yg dikirim si server jadi current working directory
                    System.out.println("ubah path");
                     for (int i=0; i<this.file_info.size(); i++){
                        String pathfromserver = this.file_info.get(i).getFile_path();
                        System.out.println(pathfromserver);
                        String regex = "test\\\\client\\\\"+this.username+"\\\\";
                        String[] p = pecah[2].split("###");
                         System.out.println("p[0] = "+p[0]);
                        String clientpathstuffed = p[0] + "\\";
                        String replacement = clientpathstuffed.replaceAll("\\\\", "\\\\\\\\");
                        String pathforclient = pathfromserver.replaceAll(regex, replacement);
                        System.out.println("path for client ("+i+") : " + pathforclient);
                        clientpath.add(pathforclient);
                    }
                    this.receiveFile(clientpath);
             }
             else{

             }
            this.receiveMessage();
        }

        
    }

    public void sendMultipleFile(ArrayList<String> file_paths) {
        OutputStream out = null;
        try {
            out = this.client.getOutputStream();
            for (int i = 0; i < this.file_info_client.size(); i++) {
                System.out.println(file_paths.get(i));
                // sendfile
                File myFile = new File(file_paths.get(i));
                byte[] head = (myFile.length() + "").getBytes();
                int d = head.length;
                for (int k = d - 1; d < 12; d++) {
                    out.write("0".getBytes());
                }
                out.write(head);
                System.out.write(head);
                System.out.println();
                FileInputStream in = new FileInputStream(myFile);
                System.out.println("Sending...");
                byte[] mb = new byte[1024];
                for (int c = in.read(mb); c > -1; c = in.read(mb)) {
                    out.write(mb, 0, c);
                }
                Thread.sleep(500);
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }//finally {
//            try {
//                out.close();
//            } catch (IOException ex) {
//                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
//            }
//        }

    }

    //kyknya perlu bikin fungsi sendFileName
    public void receiveFile(ArrayList<String> file_paths) {
        InputStream in = null;
        try {
            in = this.client.getInputStream();
            for (int i = 0; i < this.fileCount; i++) {
                OutputStream out = new FileOutputStream(file_paths.get(i));
                // open a new file
                out = new FileOutputStream(file_paths.get(i));
                // read the file size (up to 12 decimal digits long)
                byte[] buf0 = new byte[12];
                int bytesRead = 0;
                while (bytesRead < 12) {
                    if (bytesRead > 0) {
                        bytesRead += in.read(buf0, bytesRead, 12 - bytesRead);
                    } else {
                        bytesRead += in.read(buf0, 0, 12);
                    }
                }
                int fileLength = 0;
                try {
                    fileLength = new Integer(new String(buf0));
                } catch (NumberFormatException e) {
                    System.out.println(e);
                    System.exit(-1);
                }
                bytesRead = 0;
                byte[] buf = new byte[1024];
                int c;
                while (bytesRead < fileLength) {
                    if (fileLength - bytesRead > 1024) {
                        c = in.read(buf, 0, 1024);
                    } else {
                        c = in.read(buf, 0, fileLength - bytesRead);
                    }
                    bytesRead += c;
                    out.write(buf, 0, c);
                }
                //out.close();
            }

        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        } //finally {
//            try {
//                in.close();
//            } catch (IOException ex) {
//                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
//            }
//        }
    }

    public boolean isFolder(File f) {
        return f.isDirectory();
    }

    public boolean isFile(String path) {
        File f = new File(path);
        return f.isFile();
    }

    public void login(String username, String password) { //id=1
        this.sendMessage(username + ";;;" + password);
    }

    public String getDateLastModified(String path) {
        String out;
        File f = new File(path);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //System.out.println("Last Modified : " + sdf.format(f.lastModified()));
        out = sdf.format(f.lastModified()).toString();
        return out;
    }

    public String[] listFileFolder(String workingdirectory) {
        File folder = new File(workingdirectory);
        File[] listOfFiles = folder.listFiles();
        String[] list = new String[listOfFiles.length];
        int counter = 0;
        for (int i = 0; i < listOfFiles.length; i++) {
            //list[i] = listOfFiles[i].getName();

            if (listOfFiles[i].isFile()) {
                list[i] = listOfFiles[i].getName();
                counter++;
                // System.out.println("File :" + listOfFiles[i].getName());
            } else if (listOfFiles[i].isDirectory()) {
                // System.out.println("Directory :" + listOfFiles[i].getName());
            }
        }
        this.fileCount = counter;
        return list;

    }


    public void sinkronisasi(String username, String workingdirectory) {
        System.out.println("Sinkronisasi nih gan");
        //String infofile = "";

        //if (berubah) {
        //this.requestAllFilesToServer();
            String[] filecontent = listFileFolder(workingdirectory);
//            for (int i = 0; i < filecontent.length - 1; i++) {
//                if (filecontent[i] != null) {
//                    //this.fileCount = filecontent.length;
//                    this.file_info_client.add(new fileInfo(
//                            workingdirectory + "\\" + filecontent[i],
//                            Timestamp.valueOf(getDateLastModified(workingdirectory + "\\" + filecontent[i]))));
//                    //System.out.println("coba print : "+getDateLastModified(workingdirectory + "\\" +filecontent[i]));
//                    infofile += workingdirectory + "\\" + filecontent[i] + ";;;" + getDateLastModified(workingdirectory + "\\" + filecontent[i]) + "%%%";
//                }
//            }
//            infofile += workingdirectory + "\\" + filecontent[filecontent.length - 1] + ";;;" + getDateLastModified(workingdirectory + "\\" + filecontent[filecontent.length - 1]);

            //cek disini apakah mesti ngirim semua file atau request file ke server, atau do nothing
            int decision = this.cekSyncRequest();
            if ( decision == 1){
//                try {
                    //this.sendMessage(username + ";;;" + workingdirectory + "###" + infofile);
                    System.out.println("decision = 1");
                    //upload
                    for (int i = 0; i < this.file_info_client.size(); i++) {
                        System.out.println("PATH : " + this.file_info_client.get(i).getFile_path());
                    }
                    this.sendMessage(this.username + ";;;uploadfile;;;"+this.file_info_client.size());
                    String infofile = "";
                    //kirim pesan ke client
                    for(int i=0; i<this.file_info_client.size()-1; i++){
                        infofile = infofile + this.file_info_client.get(i).getFile_path() + ";;;"
                                + this.file_info_client.get(i).getDate_modified().toString() + "%%%";
                    }
                    infofile = infofile + this.file_info_client.get(this.file_info_client.size()-1).getFile_path() + ";;;"
                                + this.file_info_client.get(this.file_info_client.size()-1).getDate_modified().toString() + "%%%";
                    System.out.println("ini nih : " + this.username + ";;;" + this.workingdirectory + "###" + infofile);
                    this.workingdirectory = workingdirectory;
                    this.sendMessage(this.username + ";;;" + this.workingdirectory + "###" + infofile);
//                    Thread.sleep(2000);

                    this.sendMultipleFile(this.addFilePaths(this.file_info_client));
//                } catch (InterruptedException ex) {
//                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
//                }
            }
            else if (decision == 2){
                //this.requestAllFilesToServer();
                System.out.println("decision = 2");
                //download ke server
                //download file
                this.sendMessage(this.username+";;;downloadfile;;;"+this.workingdirectory);
            }
            else if (decision == 3){
                //this.sendMessage(username + ";;;updated");
                System.out.println("decision = 3");
                //do nothing
            }

       // } else {
       //     this.sendMessage(username + ";;;updated");
       // }
    }

    public void LogOut(String username) {
        this.sendMessage(username);
    }

    public void timeoutHandler(String cause, int time) {
    }

    public void startTimer() {
    }

    public void displayErrorMessage(String cause) {
    }
}
